1 module targets.windows; 2 version(Windows): 3 import commons; 4 import std.windows.registry; 5 static import std.file; 6 7 bool hasVCRuntime140() 8 { 9 string arch = "X64"; 10 version(Win32) arch = "X32"; 11 Key currKey = windowsGetKeyWithPath("SOFTWARE", "WOW6432Node", "Microsoft", "VisualStudio", "14.0", "VC", "Runtimes", arch); 12 return currKey.getValue("Installed").value_DWORD == 1; 13 } 14 15 pragma(lib, "ole32.lib"); 16 pragma(lib, "oleaut32.lib"); 17 bool hasMSVCLinker() 18 { 19 import core.sys.windows.winbase; 20 import core.sys.windows.winnt; 21 import core.sys.windows.com; 22 import core.sys.windows.wtypes; 23 immutable supportedPre2017Versions = ["14.0"]; 24 const GUID iid_SetupConfiguration = { 0x177F0C4A, 0x1CD3, 0x4DE7, [ 0xA3, 0x2C, 0x71, 0xDB, 0xBB, 0x9F, 0xA3, 0x6D ] }; 25 26 static interface ISetupInstance : IUnknown 27 { 28 // static const GUID iid = uuid("B41463C3-8866-43B5-BC33-2B0676F7F42E"); 29 static const GUID iid = { 0xB41463C3, 0x8866, 0x43B5, [ 0xBC, 0x33, 0x2B, 0x06, 0x76, 0xF7, 0xF4, 0x2E ] }; 30 31 int GetInstanceId(BSTR* pbstrInstanceId); 32 int GetInstallDate(LPFILETIME pInstallDate); 33 int GetInstallationName(BSTR* pbstrInstallationName); 34 int GetInstallationPath(BSTR* pbstrInstallationPath); 35 int GetInstallationVersion(BSTR* pbstrInstallationVersion); 36 int GetDisplayName(LCID lcid, BSTR* pbstrDisplayName); 37 int GetDescription(LCID lcid, BSTR* pbstrDescription); 38 int ResolvePath(LPCOLESTR pwszRelativePath, BSTR* pbstrAbsolutePath); 39 } 40 41 static interface IEnumSetupInstances : IUnknown 42 { 43 // static const GUID iid = uuid("6380BCFF-41D3-4B2E-8B2E-BF8A6810C848"); 44 45 int Next(ULONG celt, ISetupInstance* rgelt, ULONG* pceltFetched); 46 int Skip(ULONG celt); 47 int Reset(); 48 int Clone(IEnumSetupInstances* ppenum); 49 } 50 51 static interface ISetupConfiguration : IUnknown 52 { 53 // static const GUID iid = uuid("42843719-DB4C-46C2-8E7C-64F1816EFD5B"); 54 static const GUID iid = { 0x42843719, 0xDB4C, 0x46C2, [ 0x8E, 0x7C, 0x64, 0xF1, 0x81, 0x6E, 0xFD, 0x5B ] }; 55 56 int EnumInstances(IEnumSetupInstances* ppEnumInstances) ; 57 int GetInstanceForCurrentProcess(ISetupInstance* ppInstance); 58 int GetInstanceForPath(LPCWSTR wzPath, ISetupInstance* ppInstance); 59 } 60 61 62 if("VSINSTALLDIR" in environment && !("LDC_VSDIR_FORCE" in environment)) 63 { 64 if(!("VSCMD_ARG_TGT_ARCH" in environment)) 65 return true; 66 string tgtArch = environment["VSCMD_ARG_TGT_ARCH"]; 67 if(tgtArch == "x64" || tgtArch == "x32") 68 return true; 69 } 70 if("LDC_VSDIR" in environment && std.file.exists(environment["LDC_VSDIR"])) 71 return true; 72 73 bool detectVSInstallDirViaCOM() 74 { 75 import core.sys.windows.windows; 76 import core.stdc.wchar_:wcscmp; 77 78 CoInitialize(null); scope(exit) CoUninitialize(); 79 80 ISetupConfiguration setup; 81 IEnumSetupInstances instances; 82 ISetupInstance instance; 83 DWORD fetched; 84 85 HRESULT hr = CoCreateInstance(&iid_SetupConfiguration, null, CLSCTX_ALL, &ISetupConfiguration.iid, cast(void**) &setup); 86 if(hr != S_OK || !setup) return false; 87 88 scope(exit) setup.Release(); 89 if(setup.EnumInstances(&instances) != S_OK) 90 return false; 91 scope(exit) instances.Release(); 92 93 BSTR thisVersionString, thisInstallDir; 94 while (instances.Next(1, &instance, &fetched) == S_OK && fetched) 95 { 96 if(instance.GetInstallationVersion(&thisVersionString) != S_OK || 97 instance.GetInstallationPath(&thisInstallDir) != S_OK) 98 continue; 99 return true; 100 } 101 return false; 102 } 103 104 if(detectVSInstallDirViaCOM()) 105 return true; 106 107 if(Key k = windowsGetKeyWithPath("SOFTWARE", "Microsoft", "VisualStudio", "SxS", "VS7")) 108 if(k.getValue("15.0").value_SZ) 109 return true; 110 111 foreach (ver; supportedPre2017Versions) 112 { 113 Key k = windowsGetKeyWithPath("SOFTWARE", "Microsoft", "VisualStudio", ver); 114 try 115 { 116 if(k !is null && k.getValue("InstallDir")) 117 return true; 118 } 119 catch(Exception e){return false;} 120 } 121 return false; 122 } 123 124 private string getVCDownloadLink() 125 { 126 version(Win64) return "https://aka.ms/vs/17/release/vc_redist.x64.exe"; 127 else version(Win32) return "https://aka.ms/vs/17/release/vc_redist.x86.exe"; 128 else version(AArch64) return "https://aka.ms/vs/17/release/vc_redist.arm64.exe"; 129 } 130 131 private bool installVCRuntime140(ref Terminal t, ref RealTimeConsoleInput input) 132 { 133 string vcredist = buildNormalizedPath(std.file.getcwd(), "buildtools", "vcredist.exe"); 134 if(!downloadFileIfNotExists("Get Microsoft Visual C++ Redistributable for being able to compile D Programming Language", getVCDownloadLink, vcredist, t, input)) 135 { 136 t.writelnError("Needs to download VCRuntime."); 137 return false; 138 } 139 t.writelnHighlighted("Installing Microsoft Visual C++ Redistributable"); 140 141 auto ret = wait(spawnShell(vcredist~" /install /quiet /norestart")) == 0; 142 if(ret) 143 t.writelnSuccess("Successfully installed Microsoft Visual C++ Redistributable."); 144 else 145 t.writelnError("Could not install Microsoft Visual C++ Redistributable."); 146 return ret; 147 } 148 149 private bool installMSLinker(ref Terminal t, ref RealTimeConsoleInput input) 150 { 151 string vcBuildTools = buildNormalizedPath(std.file.getcwd(), "buildtools", "vc_BuildTools.exe"); 152 enum vcBuildToolsLink = "https://aka.ms/vs/17/release/vs_BuildTools.exe"; 153 if(!downloadFileIfNotExists("Get Windows SDK for being able to compile D programming language", vcBuildToolsLink, vcBuildTools, t, input)) 154 { 155 t.writelnError("Need to download vs_BuildTools.exe"); 156 return false; 157 } 158 t.writelnHighlighted("Starting Windows SDK Installation."); 159 160 string[] installList = 161 [ 162 "Microsoft.VisualStudio.Workload.VCTools", 163 "Microsoft.VisualStudio.Component.TestTools.BuildTools", 164 "Microsoft.VisualStudio.Component.VC.ASAN", 165 "Microsoft.VisualStudio.Component.VC.Tools.x86.x64" 166 ]; 167 168 import std.algorithm:reduce; 169 170 auto ret = wait(spawnShell(vcBuildTools~" --wait --passive --norestart " ~installList.reduce!((str, last) => "--add "~last~" "~str))) == 0; 171 return ret == 0; 172 } 173 174 ChoiceResult prepareWindows(Choice* c, ref Terminal t, ref RealTimeConsoleInput input, in CompilationOptions cOpts) 175 { 176 if(!hasVCRuntime140) 177 { 178 if(!installVCRuntime140(t, input)) 179 { 180 t.writelnError("Your system must install Microsoft Visual C++ 14 for using the D Programming Language."); 181 return ChoiceResult.Error; 182 } 183 } 184 if(!hasMSVCLinker) 185 { 186 if(!installMSLinker(t, input)) 187 { 188 if(hasMSVCLinker) 189 t.writelnSuccess("Succesfully installed Windows SDK."); 190 else 191 { 192 t.writelnError("Could not install Windows SDK."); 193 return ChoiceResult.Error; 194 } 195 } 196 else 197 { 198 t.writelnError("Your system must install the MSLinker. This is important for creating binaries without dependencies."); 199 return ChoiceResult.Error; 200 } 201 } 202 203 // waitOperations([{ 204 std.file.chdir(configs["gamePath"].str); 205 if(timed(() => waitDub(t, DubArguments().command("build").configuration("script").opts(cOpts)) != 0)) 206 return ChoiceResult.Error; 207 // return false; 208 // return true; 209 // }, 210 // { 211 if(!c.scriptOnly) 212 { 213 std.file.chdir(getHipPath); 214 if(timed(() => waitDub(t, DubArguments().command("build").configuration("script").opts(cOpts))) != 0) 215 return ChoiceResult.Error; 216 } 217 // return true; 218 // }]); 219 220 wait(spawnShell((getHipPath("bin", "desktop", "hipreme_engine.exe") ~ " "~ configs["gamePath"].str))); 221 222 return ChoiceResult.Continue; 223 }